package com.bjpowernode.shop.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bjpowernode.shop.constants.AuthServerConstants;
import com.bjpowernode.shop.domain.SysUser;
import com.bjpowernode.shop.domain.User;
import com.bjpowernode.shop.mapper.UserMapper;
import com.bjpowernode.shop.properties.WxProperties;
import com.bjpowernode.shop.service.SysUserService;
import com.bjpowernode.shop.mapper.SysUserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;

/**
 * @author Abai
 * @description 针对表【sys_user(系统用户)】的数据库操作Service实现
 * @createDate 2023-03-27 18:23:49
 */
@Service
// 登录时，调用的认证方法
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
        implements SysUserService, UserDetailsService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WxProperties wxProperties;

    @Autowired
    private RestTemplate restTemplate;
    

    /*
        前台用户
            请求头中loginType=user
        后台用户
            请求头中loginType=sysUser
     */

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 获取请求头，判断用户的所属类型【前台/后台】
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String userType = request.getHeader(AuthServerConstants.LOGIN_TYPE_PREFIX);

        if (StringUtils.isNotEmpty(userType)) {
            switch (userType) {
                // 前台系统用户，需要进行微信第三方登录
                case AuthServerConstants.USER:
                    // 前台将授权码的js-code作为username参数传递过来了，需要进行微信第三方登录:根据code换取token
                    // 将URL地址占位符进行赋值
                    String url = String.format(wxProperties.getUrl(), wxProperties.getAppId(), wxProperties.getAppSecret(), username);

                    // 远程调用进行第三方登录，如果登录成功，会返回openid的json数据
                    String json = restTemplate.getForObject(url, String.class);

                    // 解析json数据
                    if (StringUtils.isNotEmpty(json)) {
                        JSONObject jsonObject = JSON.parseObject(json);

                        // 获取微信返回的openid，小程序全局的唯一标识
                        if (jsonObject.containsKey("openid")) {
                            String openid = jsonObject.getString("openid");

                            // 查询数据库，openid就是我们的唯一标识用户表的
                            User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserId, openid));

                            // 如果当前用户没有注册，为其自动注册
                            if (ObjectUtils.isEmpty(user)) {
                                // 获取ip地址
                                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                                String ip = requestAttributes.getRequest().getRemoteAddr();

                                // 新建user插入数据库
                                int row = userMapper.insert(
                                        user = User.builder()
                                                .userId(openid)
                                                .loginPassword(new BCryptPasswordEncoder().encode("WECHAT"))
                                                .status(1)
                                                .modifyTime(new Date())
                                                .userRegtime(new Date())
                                                .userRegip(ip)
                                                .userLasttime(new Date())
                                                .userLastip(ip)
                                                .build()
                                );

                                if (row == 0) {
                                    throw new RuntimeException("前端用户注册失败");
                                }
                                // 用户注册成功，返回结果
                                return user;
                            }
                            // 数据库查到用户，直接返回结果
                            return user;
                        }
                    }
                    break;
                //==后台系统用户，根据用户名查询用户信息，再根据用户id查询权限信息，完成授权操作==
                case AuthServerConstants.SYS_USER:
                    // 根据用户名查询用户对象
                    SysUser user = sysUserMapper.selectOne(
                            new LambdaQueryWrapper<SysUser>()
                                    .eq(StringUtils.isNotEmpty(username), SysUser::getUsername, username)
                    );
                    if (!ObjectUtils.isEmpty(user)) {
                        // 根据用户id，查询用户的权限信息列表
                        List<String> authLists = sysUserMapper.getAuthListsById(user.getUserId());
                        if (!CollectionUtils.isEmpty(authLists)) {
                            // 授权
                            user.setAuthList(authLists);
                        }
                        return user;
                    }
            }
        }
        throw new RuntimeException("登录失败,请重试");
    }
}